package com.sxkf.template.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sxkf.core.common.sms.SendSmsService;
import com.sxkf.core.third.im.entity.UpdateUser;
import com.sxkf.core.third.im.service.YxService;
import com.sxkf.core.third.sms.ALISMSUtils;
import com.sxkf.template.entity.UserDetails;
import com.sxkf.template.service.UserDetailsService;
import com.sxkf.template.vo.request.user.UserDetailVo;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.SxkfException;
import org.jeecg.common.exception.SxkfExceptionEnum;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.CheckEmptyUtil;
import org.jeecg.common.util.RedisUtils;
import com.sxkf.template.entity.User;
import com.sxkf.template.mapper.UserMapper;
import com.sxkf.template.service.UserService;
import com.sxkf.template.utils.RandomUtil;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 张广成
 * @since 2024-11-06 15:13:33
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    private UserMapper userMapper;

    @Resource
    private SendSmsService sendSmsService;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private YxService yxService;

    @Resource
    private ALISMSUtils alismsUtils;

    private static final String CAPTCHA_PASS = "CAPTCHA_PASS:";

    private static final String CAPTCHA_PHONE = "CAPTCHA_PHONE:";
    @Resource
    private UserDetailsService userDetailsService;


    @Override
    public User loginByCode(String phone, String code) {
        //先从redis中查询出来存储的验证码
        String redisCode = redisUtils.get(phone + "login");
        if (redisCode != null) {
            if (redisCode.equals(code)) {
                redisUtils.del(phone + "login");
                //从数据库中查询该用户
                return userMapper.selectOne(new QueryWrapper<User>().eq("phone", phone));
            }
            throw new SxkfException(SxkfExceptionEnum.CODE_ERROR);
        } else {
            throw new SxkfException(SxkfExceptionEnum.CODE_OUT);
        }
    }

    @Override
    public void getPhoneCode(String phone, String type) {
        //String templateId, String tel, String[] templateParamSet
        //1表示营销短信，2表示通知短信，3表示验证码短信。
        String templateId = "3";
        String code = RandomUtil.generateRandomCode();
        String[] templateParamSet = {code};
        SendSmsResponse sendSmsResponse = sendSmsService.sendSms(templateId, phone, templateParamSet);
        if ("OK".equals(sendSmsResponse.getSendStatusSet()[0].getCode())) {
            log.info("短信发送成功" + sendSmsResponse.getSendStatusSet()[0].getCode());
            //将验证码存入redis中，并设置过期时间
            redisUtils.set(phone + type, code, 60 * 5);
        } else {
            log.info("短信发送失败: " + sendSmsResponse.getSendStatusSet()[0].getMessage());
        }
    }

    @Override
    public Integer userRegister(User users) {
        //先判断手机号是否已注册过
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("phone", users.getPhone()));
        if (user != null) {
            throw new SxkfException("该手机号已注册，若忘记密码，请找回");
        }
        //判断验证码是否输入正确
        String redisCode = redisUtils.get(users.getPhone() + "register");
        if (redisCode.equals(users.getCode())) {
            //将用户信息插入到数据库中
            return userMapper.insert(users);
        }
        return null;
    }

    @Override
    public LoginUser getLoginUser(String userId) {
        User user = getById(userId);
//        log.info("user:{}", user);
        LoginUser loginUser = new LoginUser();

        //BeanUtils.copyProperties(user, loginUser);

        loginUser.setUsername("user::" + userId);
//        log.info("password:{}", user.getPassword());
        loginUser.setPassword(user.getPassword());
//        log.info("password:{}", loginUser.getPassword());
//        log.info("loginUser:{}", loginUser);
        return loginUser;


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUser(User user) {
        User userInfo = getById(user.getId());
        boolean update = updateById(user);
        if (update) {
            UpdateUser updateUser = new UpdateUser();
            if (CheckEmptyUtil.isNotEmpty(user.getNickName()) && userInfo.getNickName() != user.getNickName()) {
                updateUser.setName(user.getNickName());
            }
            if (CheckEmptyUtil.isNotEmpty(user.getAvatar()) && userInfo.getAvatar() != user.getAvatar()) {
                updateUser.setAvatar(user.getAvatar());
            }
            Boolean aBoolean = yxService.updateUser(user.getId(), updateUser);
            if (aBoolean) {
                return aBoolean;
            }
        }
        throw new SxkfException("操作失败！");
    }

    @Override
    public void sendCaptcha(String phoneNumber) {
        String code = creatCode();
        alismsUtils.sendSMS(phoneNumber, code);
        redisUtils.set(CAPTCHA_PASS + phoneNumber, code, 120);
        System.out.println(phoneNumber + "的验证码为:" + code);
    }

    @Override
    public void updatePass(String id, String captcha, String newPass) {
        User user = getById(id);
        String captchaCode = redisUtils.get(CAPTCHA_PASS + user.getPhone());
        if (CheckEmptyUtil.isEmpty(captchaCode)) {
            throw new SxkfException("验证码已过期");
        }
        if (!captchaCode.equals(captcha)) {
            throw new SxkfException(SxkfExceptionEnum.CODE_ERROR);
        }
        user.setPassword(newPass);
        updateById(user);
        redisUtils.del(CAPTCHA_PASS + user.getPhone());
    }

    @Override
    public Boolean checkPhoneCode(String phoneNumber, String code) {
        String oldCode = redisUtils.get(CAPTCHA_PHONE + phoneNumber);
        if (CheckEmptyUtil.isEmpty(oldCode)) {
            throw new SxkfException("验证码已过期");
        }
        if (!oldCode.equals(code)) {
            throw new SxkfException("验证码错误");
        }
        return true;
    }

    @Override
    public void updatePhone(String id, String captcha, String newPhone) {
        User user = getById(id);
        String captchaCode = redisUtils.get(CAPTCHA_PHONE + newPhone);
        if (CheckEmptyUtil.isEmpty(captchaCode)) {
            throw new SxkfException("验证码已过期");
        }
        if (!captchaCode.equals(captcha)) {
            throw new SxkfException(SxkfExceptionEnum.CODE_ERROR);
        }
        user.setPhone(newPhone);
        updateById(user);
        redisUtils.del(CAPTCHA_PHONE + user.getPhone());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean realNameUser(UserDetailVo userDetailVo) {

        User user = getById(userDetailVo.getUserId());

        if (CheckEmptyUtil.isEmpty(user)) {
            throw new SxkfException("用户不存在");
        }
        if (user.getIsAuth().equals("1")) {
            throw new SxkfException("用户已实名");
        }

        UserDetails userDetails = new UserDetails();
        userDetails.setId(userDetailVo.getUserId());
        userDetails.setName(userDetailVo.getName());
        userDetails.setIdNumber(userDetailVo.getIdNumber());
        userDetails.setName(userDetailVo.getName());
        // todo 暂时不接二要素
//        try {
//            userDetailsService.realNameUser(userDetails);
//        } catch (TencentCloudSDKException e) {
//            throw new RuntimeException(e);
//        }

        boolean save = userDetailsService.save(userDetails);
        if (save) {
            user.setRealName(userDetailVo.getName());
            user.setIsAuth("1");
            user.setIdCard(userDetailVo.getIdNumber());
            return updateById(user);
        }


        throw new SxkfException("实名失败");
    }

    @Override
    public Boolean byebye(String userId, HttpServletRequest request) {

        String tokenRes = JwtUtil.getUserNameByToken(request);
        String tokenUserId = tokenRes.split("::")[tokenRes.split("::").length - 1];

        if (tokenUserId.equals(userId)) {
            return removeById(userId);
        }
        throw new SxkfException("注销失败");
    }

    @Override
    public void loadLocation(String userId, Double longitude, Double latitude) {
        redisUtils.addGeo(CommonConstant.LOCATION, longitude, latitude, userId);
    }

    @Override
    public IPage<User> nearby(Integer pageNo, Integer pageSize, Double longitude, Double latitude) {
        IPage<User> userPage = new Page<>(pageNo, pageSize);

        int from = (pageNo - 1) * pageSize;
        int end = pageNo * pageSize;

        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = redisUtils.search(CommonConstant.LOCATION, longitude, latitude, 5000d, end);
        if (geoResults != null) {
            List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = geoResults.getContent();
            if (list.size() >= from){
                List<String> ids = new ArrayList<>(list.size());
                Map<String, Distance> distanceMap = new HashMap<>(list.size());
                list.stream().skip(from).forEach(item->{
                    String userId = item.getContent().getName();
                    ids.add(userId);

                    Distance distance = item.getDistance();
                    distanceMap.put(userId,distance);
                });

                List<User> records = listByIds(ids);
                records.forEach(item->{
                    Distance distance = distanceMap.get(item.getId());
                    item.setDistance(distance);
                });

                userPage.setRecords(records);
                userPage.setTotal(9999L);
                userPage.setPages(999L);
            }
        }
        return userPage;
    }

    private String creatCode() {
        SecureRandom random = new SecureRandom();
        int i = random.nextInt(899999) + 100000;
        return i + "";
    }

}
